import path from 'path'
import config from '@/config'
import { Connect } from '@/connect'
import { SendActionGroup } from './actions/group/send'
import { ReceiveVerifyAction } from './actions/verify'
import type { Server } from '.'
import type { Socket } from 'net'
import type { Project } from './project'
import type { LimitResult } from './limiter'
import type { Packet } from '@/connect/packet'

export class ServerConnect extends Connect {
  constructor(socket: Socket, server: Server) {
    super(socket, path.join(config.globalLogDir, 'connect/server'))
    this.serverInstance = server
    this._isConnected = true // 服务端不会触发connect事件，所以默认为连接成功
    this.limitResult = this.limiter.getLimitResult(this.remoteAddressInfo.address)
    this.ownBindEvent()
    this.checkLimit()
    this.initAction()

    this.logger.info('connect')
  }

  readonly serverInstance: Server

  readonly limitResult: LimitResult

  project: Project | null = null

  /**
   * 当前连接是否验证通过
   */
  verified?: boolean

  get limiter() {
    return this.serverInstance.limiter
  }

  protected ownBindEvent() {
    this.on('error', () => {
      // 有错误直接结束连接，防止服务端挂掉
      this.end()
    })

    this.on('end', () => {
      this.logger.info('disconnect')
      if (!this.limitResult.isLimited && this.verified === void 0) {
        // 如果未验证，则添加一条验证失败记录
        this.limiter.addVerifyFailureRecord(this.remoteAddressInfo.address)
      }
    })
  }

  protected async checkLimit() {
    if (this.limitResult.isLimited) {
      this.logger.info(`${this.remoteAddressInfo.address} is limited`, this.limitResult)
      if (this.limitResult.tip) {
        await this.sendFatalError(this.limitResult.tip)
      }
      this.end()
    }
  }

  protected initAction() {
    this.addAction(new ReceiveVerifyAction(this))
    this.addAction(new SendActionGroup(this))

    this.runAction('receiveConnect')
      .then(() => this.runAction('receiveVerify'))
      .then((name) => this.runAction(name || ''))
      .then(() => {
        this.end()
      })
      .catch((err) => {
        this.logger.error(err)
        this.end()
      })
  }

  async send(packet: Packet) {
    return super.send(packet).catch((err) => {
      this.logger.error(err)
    })
  }

  get debugConfig() {
    return this.serverInstance.debugConfig
  }
}
